package main

import (
	"net/http"
	"regexp"
	"text/template"
	"strings"
	"io/ioutil"
	"log"
)

type Article struct {
	Title string
	Body []byte
}

var titleValidator=regexp.MustCompile("^[a-zA-Z0-9]+$")
var templates=make(map[string]*template.Template)

func init() {
	templates["view"]=template.Must(template.ParseFiles("template/view.html"))
	templates["edit"]=template.Must(template.ParseFiles("template/edit.html"))
}

func main() {
	http.HandleFunc("/view/", makeHandler(viewHandler))
	http.HandleFunc("/edit/", makeHandler(editHandler))
	http.HandleFunc("/save/", makeHandler(saveHandler))

	http.ListenAndServe("localhost:3000", nil)
}

func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request){
		title:=getTitle(req.URL.Path)
		log.Println("title:", title)
		if !titleValidator.MatchString(title) {
			http.Error(w,"invalid title", http.StatusInternalServerError)
			return
		}
		fn(w,req,title)
	}
}

func getTitle(path string) string {
	index:=strings.LastIndex(path,"/")
	return path[index+1:]
}

func renderTemplate(w http.ResponseWriter, t *template.Template, data interface{}) {
	err:=t.Execute(w, data)
	if err!=nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func viewHandler(w http.ResponseWriter, req *http.Request, title string) {
	filename:="data/" + title + ".txt"
	body,err:=ioutil.ReadFile(filename)
	if err!=nil {
		http.Redirect(w,req, "/edit/" + title, http.StatusFound)
		return
	}
	article:=Article{Title:title, Body: body}
	renderTemplate(w, templates["view"], &article)
}

func editHandler(w http.ResponseWriter, req *http.Request, title string) {
	filename:="data/" + title + ".txt"
	body,err:=ioutil.ReadFile(filename)
	var article Article
	if err!=nil {
		article=Article{Title:title}
	} else {
		article=Article{Title:title, Body: body}
	}
	renderTemplate(w, templates["edit"], &article)
}

func saveHandler(w http.ResponseWriter, req *http.Request, title string) {
	filename:="data/" + title + ".txt"
	body:=[]byte(req.FormValue("body"))
	err:=ioutil.WriteFile(filename, body, 0666)
	if err!=nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	} else {
		http.Redirect(w, req, "/view/" + title, http.StatusFound)
	}
}
